#pragma once
#include<string>
#include<memory>
#include"../comm/log.hpp"
#include"../comm/jsoncpp.hpp"
#include"../comm/httplib.h"
#include"../comm/RegistCenter.hpp"
namespace Ns_Load
{
    using namespace std;
    using namespace httplib;
    using namespace Ns_Log;
    struct Machine
    {
        Machine(const string& ip_port)
        :_ip_port(ip_port),_cptr(make_shared<Client>(ip_port))
        {
            //设置连接超时、读取超时和写入超时
            _cptr->set_connection_timeout(0, 300000); // 300 milliseconds
            _cptr->set_read_timeout(20, 0); // 20 seconds
            _cptr->set_write_timeout(5, 0); // 5 seconds
        }
        string _ip_port;
        shared_ptr<Client> _cptr;
    };
    class MachineManagement
    {
        private:
        int index=0;
        vector<Machine> machine_list;
        mutex _mutex;
        public:
        void debug()
        {
            log(INFO,"当前编译服务存在"+to_string(machine_list.size())+"台");
            for(auto m:machine_list)
            {
                log(INFO,"服务: "+m._ip_port);
            }
        }
        void add(const string& servicename,const string& ip_port)
        {
            lock_guard<mutex> guard(_mutex);
            machine_list.push_back(Machine(ip_port));
        }
        void del(const string& servicename,const string& ip_port)
        {
            lock_guard<mutex> guard(_mutex);
            auto it=machine_list.begin();
            while(it!=machine_list.end())
            {
                if((*it)._ip_port==ip_port)
                {
                    machine_list.erase(it);
                    break;
                }
                ++it;
            }
        }
        void getMachine(shared_ptr<Client>& cli)
        {
            lock_guard<mutex> guard(_mutex);
            int pos=index;
            if(pos>=machine_list.size())
            pos=0;
            index=(index+1)%machine_list.size();
            cli=machine_list[pos]._cptr;
        }
    };
    class LoadBalancer
    {
    private:
       MachineManagement mm;
       etcdtools::RegistCenter cen;
    public:
        LoadBalancer()
        :mm(),cen("127.0.0.1:2379","/service",bind(&MachineManagement::add,&mm,std::placeholders::_1,std::placeholders::_2),bind(&MachineManagement::del,&mm,std::placeholders::_1,std::placeholders::_2))
        {
            cen.Start();
            mm.debug();
        }
        //in_json{code:?,stdin:?,t_limit:?,s_limit:?}
        bool judge(const string& code,const string& stdin_,const string& t_limit,const string& s_limit,int& status,string& result_message)
        {
            //获取一台机器
            shared_ptr<Client> cli;
            mm.getMachine(cli);
            
            //序列化请求数据
            Json::Value root;
            root["code"]=code;
            root["stdin"]=stdin_;
            //将1S->1，2MB->2
            string tt=t_limit;
            string ss=s_limit;
            root["t_limit"]=tt.substr(0,tt.find('S'));
            root["s_limit"]=ss.substr(0,ss.find('M'));
            string request_json;
            if(!Serialize(root,request_json))
            log(ERROR,"编译请求序列化失败!");
            
            auto res=cli->Post("/compile_run",httplib::Headers(),request_json,"application/json;charset=UTF-8");
            if (res && res->status == 200)
            {
                //反序列化
                Json::Value root;
                UnSerialize(root,res->body);
                status=root["status"].asInt();
                result_message=root["result_message"].asString();
                return true;
            }
            else
            {
                log(ERROR,"请求编译服务，响应错误，错误码: "+res->status);
                return false;
            }
        }    
    };
}
